package com.example.nginx;

import org.apache.commons.cli.*;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;

/**
 * Nginx访问日志模拟生成器
 * 支持随机生成nginx访问日志并输出到指定文件
 * 支持日志按大小和时间轮转
 */
public class NginxLogGenerator {
    
    private static final Logger logger = Logger.getLogger(NginxLogGenerator.class.getName());
    
    private static final String LOG_FORMAT = "%s - %s [%s] \"%s\" %d %d \"%s\" \"%s\" \"%s\" %s %.3f %s";
    
    // 随机数据池
    private static final String[] IP_ADDRESSES = {
        "192.168.1.100", "192.168.1.101", "192.168.1.102", "10.0.0.1", "10.0.0.2",
        "172.16.0.1", "172.16.0.2", "203.0.113.1", "198.51.100.1", "10.130.40.52"
    };
    
    private static final String[] USER_AGENTS = {
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15",
        "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
        "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0",
        "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:89.0) Gecko/20100101 Firefox/89.0"
    };
    
    private static final String[] HTTP_METHODS = {"GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS"};
    
    private static final String[] PATHS = {
        "/", "/index.html", "/api/users", "/api/products", "/api/orders", "/login", "/logout",
        "/dashboard", "/profile", "/settings", "/api/auth/login", "/api/auth/logout",
        "/static/css/style.css", "/static/js/app.js", "/images/logo.png", "/favicon.ico",
        "/prod-api/system/dict/data/type/sys_job_group", "/prod-api/monitor/job/list",
        "/prod-api/druid/login.html", "/prod-api/getRouters", "/d3/system/config"
    };
    
    private static final String[] REFERERS = {
        "-", "http://localhost:8080/", "http://example.com/", "https://www.google.com/",
        "http://10.130.25.203:8000/d3/monitor/job", "http://10.130.25.203:8000/d3/monitor/druid"
    };
    
    private static final String[] UPSTREAM_ADDRESSES = {
        "10.130.25.203:8088", "192.168.1.10:8080", "10.0.0.10:9000", "-"
    };
    
    private static final int[] STATUS_CODES = {200, 201, 204, 301, 302, 400, 401, 403, 404, 500, 502, 503};
    
    private final Random random = new Random();
    private final SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MMM/yyyy:HH:mm:ss Z", Locale.ENGLISH);
    private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    
    private String outputFile;
    private int logsPerSecond;
    private boolean running = false;
    
    // 日志轮转管理器
    private LogRotationManager rotationManager;
    
    public NginxLogGenerator(String outputFile, int logsPerSecond) {
        this.outputFile = outputFile;
        this.logsPerSecond = logsPerSecond;
        this.rotationManager = null;
    }
    
    /**
     * 带日志轮转的构造函数
     */
    public NginxLogGenerator(String outputFile, int logsPerSecond, LogRotationManager rotationManager) {
        this.outputFile = outputFile;
        this.logsPerSecond = logsPerSecond;
        this.rotationManager = rotationManager;
    }
    
    /**
     * 生成单条日志记录
     */
    private String generateLogEntry() {
        String remoteAddr = IP_ADDRESSES[random.nextInt(IP_ADDRESSES.length)];
        String remoteUser = "-"; // 通常为-
        String timeLocal = dateFormat.format(new Date());
        String method = HTTP_METHODS[random.nextInt(HTTP_METHODS.length)];
        String path = PATHS[random.nextInt(PATHS.length)];
        String request = String.format("%s %s HTTP/1.1", method, path);
        int status = STATUS_CODES[random.nextInt(STATUS_CODES.length)];
        int bodyBytesSent = random.nextInt(100000) + 100; // 100-100099 bytes
        String httpReferer = REFERERS[random.nextInt(REFERERS.length)];
        String httpUserAgent = USER_AGENTS[random.nextInt(USER_AGENTS.length)];
        String httpXForwardedFor = "-";
        String requestUri = path;
        double requestTime = random.nextDouble() * 2.0; // 0-2秒
        String upstreamAddr = UPSTREAM_ADDRESSES[random.nextInt(UPSTREAM_ADDRESSES.length)];
        
        return String.format(LOG_FORMAT, 
            remoteAddr, remoteUser, timeLocal, request, status, bodyBytesSent,
            httpReferer, httpUserAgent, httpXForwardedFor, requestUri, requestTime, upstreamAddr);
    }
    
    /**
     * 写入日志到文件
     */
    private void writeLogs() {
        try {
            // 如果启用了日志轮转，使用轮转管理器写入
            if (rotationManager != null && rotationManager.isEnabled()) {
                for (int i = 0; i < logsPerSecond; i++) {
                    String logEntry = generateLogEntry();
                    rotationManager.writeLog(logEntry);
                }
            } else {
                // 使用传统的文件写入方式
                try (FileWriter writer = new FileWriter(outputFile, true);
                     BufferedWriter bufferedWriter = new BufferedWriter(writer)) {
                    
                    for (int i = 0; i < logsPerSecond; i++) {
                        String logEntry = generateLogEntry();
                        bufferedWriter.write(logEntry);
                        bufferedWriter.newLine();
                    }
                    bufferedWriter.flush();
                    
                } catch (IOException e) {
                    System.err.println("写入日志文件时发生错误: " + e.getMessage());
                }
            }
            
        } catch (Exception e) {
            System.err.println("写入日志时发生错误: " + e.getMessage());
        }
    }
    
    /**
     * 开始生成日志
     */
    public void start() {
        if (running) {
            System.out.println("日志生成器已经在运行中...");
            return;
        }
        
        running = true;
        System.out.println("开始生成nginx访问日志...");
        System.out.println("输出文件: " + outputFile);
        System.out.println("每秒生成条数: " + logsPerSecond);
        System.out.println("按 Ctrl+C 停止生成");
        
        // 每秒执行一次日志生成
        scheduler.scheduleAtFixedRate(this::writeLogs, 0, 1, TimeUnit.SECONDS);
    }
    
    /**
     * 停止生成日志
     */
    public void stop() {
        if (!running) {
            return;
        }
        
        running = false;
        scheduler.shutdown();
        
        // 关闭日志轮转管理器
        if (rotationManager != null) {
            rotationManager.close();
        }
        
        try {
            if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) {
                scheduler.shutdownNow();
            }
        } catch (InterruptedException e) {
            scheduler.shutdownNow();
            Thread.currentThread().interrupt();
        }
        System.out.println("日志生成已停止");
    }
    
    /**
     * 主方法
     */
    public static void main(String[] args) {
        Options options = new Options();
        
        options.addOption("o", "output", true, "输出日志文件路径 (默认: access.log)");
        options.addOption("r", "rate", true, "每秒生成日志条数 (默认: 10)");
        options.addOption("c", "config", true, "配置文件路径 (默认: config.properties)");
        options.addOption("h", "help", false, "显示帮助信息");
        
        CommandLineParser parser = new DefaultParser();
        HelpFormatter formatter = new HelpFormatter();
        
        try {
            CommandLine cmd = parser.parse(options, args);
            
            if (cmd.hasOption("h")) {
                formatter.printHelp("nginx-log-generator", options);
                return;
            }
            
            // 加载配置
            String configFile = cmd.getOptionValue("c", "config.properties");
            ConfigurationLoader configLoader = new ConfigurationLoader(configFile);
            
            // 打印当前配置
            configLoader.printConfiguration();
            
            String outputFile;
            int logsPerSecond;
            
            // 命令行参数优先于配置文件
            if (cmd.hasOption("o")) {
                outputFile = cmd.getOptionValue("o");
            } else {
                outputFile = configLoader.getOutputFile();
            }
            
            if (cmd.hasOption("r")) {
                logsPerSecond = Integer.parseInt(cmd.getOptionValue("r"));
            } else {
                logsPerSecond = configLoader.getLogsPerSecond();
            }
            
            if (logsPerSecond <= 0) {
                System.err.println("每秒生成条数必须大于0");
                return;
            }
            
            // 创建日志轮转管理器
            LogRotationManager rotationManager = null;
            if (configLoader.isRotationEnabled()) {
                rotationManager = new LogRotationManager(
                    outputFile,
                    configLoader.isRotationEnabled(),
                    configLoader.getMaxFileSize(),
                    configLoader.getTimeInterval(),
                    configLoader.getMaxFiles(),
                    configLoader.getFilePattern(),
                    configLoader.getRotationDirectory()
                );
            }
            
            NginxLogGenerator generator;
            if (rotationManager != null) {
                generator = new NginxLogGenerator(outputFile, logsPerSecond, rotationManager);
            } else {
                generator = new NginxLogGenerator(outputFile, logsPerSecond);
            }
            
            // 添加关闭钩子
            Runtime.getRuntime().addShutdownHook(new Thread(generator::stop));
            
            generator.start();
            
        } catch (ParseException e) {
            System.err.println("解析命令行参数时发生错误: " + e.getMessage());
            formatter.printHelp("nginx-log-generator", options);
        } catch (NumberFormatException e) {
            System.err.println("每秒生成条数必须是有效的数字");
        } catch (Exception e) {
            System.err.println("启动日志生成器时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
}
